<!DOCTYPE html>
<html>
	<head>
		<title>Threejs使用LOD根据摄像机远近显示不同的物体</title>
		<meta charset="UTF-8">
		<script type="text/javascript" src="libs/statistics.js"></script>
		<script type="text/javascript" src="libs/steak.js"></script>
		<script type="text/javascript" src="libs/three.js"></script>
		<script type="text/javascript" src="libs/OrbitControls.js"></script>
		<script type="text/javascript" src="libs/OBJLoader.js"></script>
		<script type="text/javascript" src="libs/MTLLoader.js"></script>
		<style>
			body {
				margin: 0;
				overflow: hidden;
			}
		</style>
		<link href='libs/nprogress.css' rel='stylesheet' />
	</head>
	<body>
		<div id="dom"></div>
		<script type="text/javascript">
			var camera;
			var renderer;
			var mesh = [];

			function init() {
				// 创建一个场景，它将包含我们所有的元素，如物体，相机和灯光。
				var scene = new THREE.Scene();

				var urls = [
					'assets/bgImage/skyBox/posx.jpg',
					'assets/bgImage/skyBox/negx.jpg',
					'assets/bgImage/skyBox/posy.jpg',
					'assets/bgImage/skyBox/negy.jpg',
					'assets/bgImage/skyBox/posz.jpg',
					'assets/bgImage/skyBox/negz.jpg'
				];

				var lod = new THREE.LOD();
				var cubeLoader = new THREE.CubeTextureLoader();
				scene.background = cubeLoader.load(urls);

				// 创建一个摄像机，它定义了我们正在看的地方
				camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
				// 将摄像机对准场景的中心
				camera.position.x = 10;
				camera.position.y = 50;
				camera.position.z = 90;
				camera.lookAt(scene.position);
				var orbit = new THREE.OrbitControls(camera);

				// 创建一个渲染器并设置大小，WebGLRenderer将会使用电脑显卡来渲染场景
				renderer = new THREE.WebGLRenderer({
					antialias: true,
					logarithmicDepthBuffer: true,
				});
				renderer.setSize(window.innerWidth, window.innerHeight);
				// 基础光源，并应用到场景
				scene.add(new THREE.AmbientLight("#ffffff", 1.5));

				// 在屏幕上显示坐标轴
				var axes = new THREE.AxisHelper(100);
				scene.add(axes);

				// 将平面添加到场景中
				var plane = createPlaneGeometryBasicMaterial();
				scene.add(plane);

				// 将立方体添加到场景中
				var cube = createBoxGeometryBasicMaterial();
				lod.addLevel(cube, 200);
				// scene.add(cube);

				var cube_img = createBoxGeometryBasicMaterialImg();
				lod.addLevel(cube_img, 100);
				scene.add(cube_img);

				// 将球体添加到场景中
				var sphere = createSphereGeometryLambertMaterial();
				lod.addLevel(sphere, 300);
				scene.add(sphere);
				
				// lod.position.z = -300
				scene.add(lod);

				// 将呈现器的输出添加到HTML元素
				document.getElementById("dom").appendChild(renderer.domElement);

				// 启动动画
				renderScene();

				/**
				 * 创建地面并添加材质
				 * wrapS属性定义的是纹理沿x轴方向的行为，而warpT属性定义的是纹理沿y轴方向的行为。
				 * Three.js为这些属性提供了如下两个选项：
				 * ·THREE.RepeatWrapping允许纹理重复自己。
				 * ·THREE.ClampToEdgeWrapping是属性的默认值。
				 * 属性值为THREE.ClampToEdgeWrapping时，那么纹理的整体不会重复，只会重复纹理边缘的像素来填满剩下的空间。
				 */
				function createPlaneGeometryBasicMaterial() {
					var textureLoader = new THREE.TextureLoader();
					var cubeMaterial = new THREE.MeshStandardMaterial({
						map: textureLoader.load("assets/textures/cd.jpg"),
					});
					cubeMaterial.map.wrapS = THREE.RepeatWrapping;
					cubeMaterial.map.wrapT = THREE.RepeatWrapping;
					cubeMaterial.map.repeat.set(180, 180)
					// 创建地平面并设置大小
					var planeGeometry = new THREE.PlaneGeometry(1200, 1200);
					var plane = new THREE.Mesh(planeGeometry, cubeMaterial);

					// 设置平面位置并旋转
					plane.rotation.x = -0.5 * Math.PI;
					plane.position.x = 0;
					plane.position.z = 0;
					return plane;
				}

				// 创建一个基础材质的立方体
				function createBoxGeometryBasicMaterialImg() {
					var texture = THREE.ImageUtils.loadTexture("assets/textures/brick-wall.jpg");
					var mat = new THREE.MeshPhongMaterial();
					mat.map = texture;
					// 创建一个立方体并设置大小
					var cubeGeometry = new THREE.BoxGeometry(8, 8, 8);
					var cube = new THREE.Mesh(cubeGeometry, mat);
					// 设置立方体位置
					cube.position.x = -10;
					cube.position.y = 3;
					cube.position.z = 0;
					return cube;
				}


				// 创建一个基础材质的立方体
				function createBoxGeometryBasicMaterial() {
					// 创建一个立方体并设置大小
					var cubeGeometry = new THREE.BoxGeometry(14, 14, 4);
					// MeshBasicMaterial（基础材质不会对光源有反应只会使用指定的颜色渲染）
					var cubeMaterial = new THREE.MeshBasicMaterial({
						color: 0xff0000,
					});
					var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
					// 设置立方体位置
					cube.position.x = -5;
					cube.position.y = 10;
					cube.position.z = -30;
					return cube;
				}

				// 创建一个球形几何体
				function createSphereGeometryLambertMaterial() {
					var textureLoader = new THREE.TextureLoader();
					// 创建一个球体
					var sphereGeometry = new THREE.SphereGeometry(4, 20, 20);
					var cubeMaterial = new THREE.MeshStandardMaterial({
						map: textureLoader.load("assets/textures/brick-wall.jpg"),
					});
					// cubeMaterial.map.wrapS = THREE.RepeatWrapping;
					// cubeMaterial.map.wrapT = THREE.RepeatWrapping;
					var sphere = new THREE.Mesh(sphereGeometry, cubeMaterial);
					// 位置范围
					sphere.position.x = 20;
					sphere.position.y = 4;
					sphere.position.z = 2;
					return sphere;
				}

				document.addEventListener('click', onDocumentMouseDown, false); //监听单击拾取对象初始化球体

				function onDocumentMouseDown(event) {
					// 点击屏幕创建一个向量
					var vector = new THREE.Vector3((event.clientX / window.innerWidth) * 2 - 1, -(event.clientY / window
						.innerHeight) * 2 + 1, 0.5);
					vector = vector.unproject(camera); // 将屏幕的坐标转换成三维场景中的坐标
					var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
					var intersects = raycaster.intersectObjects(mesh.children, true);
					console.log(intersects)
					if (intersects.length > 0) {
						// intersects[0].object.material.color.set("#006100");
					}
				}

				function renderScene() {
					orbit.update();
					lod.update(camera)
					// 使用requestAnimationFrame函数进行渲染
					renderer.render(scene, camera);
					requestAnimationFrame(renderScene);
				}

				// 渲染的场景
				renderer.render(scene, camera);
			}
			window.onload = init;

			// 随着窗体的变化修改场景
			function onResize() {
				camera.aspect = window.innerWidth / window.innerHeight;
				camera.updateProjectionMatrix();
				renderer.setSize(window.innerWidth, window.innerHeight);
			}
			// 监听窗体调整大小事件
			window.addEventListener('resize', onResize, false);
		</script>
	</body>
</html>
